package com.test.okhttp;

import okhttp3.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.activation.MimetypesFileTypeMap;
import java.io.File;
import java.nio.charset.Charset;
import java.util.Map;

@Component
public class OkHttpUtils {

    @Autowired
    private OkHttpClient okHttpClient;

    private MimetypesFileTypeMap typeMap = new MimetypesFileTypeMap();

    private static final Charset CHARSET_UTF8 = Charset.forName("utf-8");

    /**
     * 同步Get请求，返回utf8编码的字符串
     *
     * @param url
     * @return
     * @throws Exception
     */
    public String syncGetStr(String url) throws Exception {
        return syncGet(url, CHARSET_UTF8);
    }

    /**
     * 同步Post请求，Post提交(form-data)方式，指定返回编码为UTF-8
     *
     * @param url
     * @param params
     * @return
     * @throws Exception
     */
    public String syncPostMap(String url, Map<String, String> params) throws Exception {
        return syncPostMap(url, params, CHARSET_UTF8);
    }

    /**
     * Post提交(application-json)方式，指定返回编码为UTF-8
     *
     * @param url
     * @param jsonStr
     * @return
     * @throws Exception
     */
    public String syncPostJson(String url, String jsonStr) throws Exception {
        return syncPostJson(url, jsonStr, CHARSET_UTF8);
    }

    /**
     * Post提交(multipart/form-data)方式，指定返回编码为UTF-8
     *
     * @param url
     * @param params
     * @return
     * @throws Exception
     */
    public String syncPostFile(String url, Map<String, Object> params) throws Exception {
        return syncPostFile(url, params, CHARSET_UTF8);
    }

    /**
     * 同步Post请求，Post提交(form-data)方式
     *
     * @param url
     * @param params
     * @return
     * @throws Exception
     */
    public String syncPostMap(String url, Map<String, String> params, Charset charset) throws Exception {
        FormBody.Builder builder = new FormBody.Builder();
        params.forEach((key, value) -> {
            builder.add(key, value);
        });
        return syncPost(url, builder.build(), charset);
    }

    /**
     * Post提交(application-json)方式
     *
     * @param url
     * @param jsonStr
     * @return
     * @throws Exception
     */
    public String syncPostJson(String url, String jsonStr, Charset charset) throws Exception {
        MediaType mediaType = MediaType.parse("application/json; charset=utf-8");
        RequestBody body = RequestBody.create(mediaType, jsonStr);
        return syncPost(url, body, charset);
    }

    /**
     * Post提交(multipart/form-data)方式
     *
     * @param url
     * @param params
     * @return
     * @throws Exception
     */
    public String syncPostFile(String url, Map<String, Object> params, Charset charset) throws Exception {
        // 构建请求数据
        MultipartBody.Builder builder = new MultipartBody.Builder();
        builder.setType(MultipartBody.FORM);
        params.forEach((key, value) -> {
            if (value instanceof File) {
                File file = (File) value;
                builder.addFormDataPart(key, file.getName(), RequestBody.create(getMediaType(file), file));
            } else {
                builder.addFormDataPart(key, (String) value);
            }
        });
        return syncPost(url, builder.build(), charset);
    }

    /**
     * 同步Get请求，返回指定编码的字符串
     *
     * @param url
     * @param charset
     * @return
     * @throws Exception
     */
    public String syncGet(String url, Charset charset) throws Exception {
        Response res = syncGet(url);
        return new String(res.body().bytes(), charset);
    }

    /**
     * 同步Post请求，返回指定编码的字符串
     *
     * @param url
     * @param body
     * @param charset
     * @return
     * @throws Exception
     */
    public String syncPost(String url, RequestBody body,  Charset charset) throws Exception {
        Response res = syncPost(url, body);
        return new String(res.body().bytes(), charset);
    }

    /**
     * 同步Get请求，返回响应对象
     *
     * @param url
     * @return
     * @throws Exception
     */
    public Response syncGet(String url) throws Exception {
        Request request = new Request.Builder().get().url(url).build();
        Response res = okHttpClient.newCall(request).execute();
        return res;
    }

    /**
     * 同步Post请求，返回响应对象
     *
     * @param url
     * @param body
     * @return
     * @throws Exception
     */
    public Response syncPost(String url, RequestBody body) throws Exception {
        Request request = new Request.Builder().post(body).url(url).build();
        Response res = okHttpClient.newCall(request).execute();
        return res;
    }

    /**
     * 异步Get请求，逻辑需要在回调对象里处理
     *
     * @param url
     * @param callback
     */
    public void asyncGet(String url, Callback callback) {
        Request request = new Request.Builder().get().url(url).build();
        enqueue(request, callback);
    }

    /**
     * 异步Post请求，逻辑需要在回调对象里处理
     *
     * @param url
     * @param body
     * @param callback
     */
    public void asyncPost(String url, RequestBody body, Callback callback) {
        Request request = new Request.Builder().post(body).url(url).build();
        enqueue(request, callback);
    }

    /**
     * 异步调用
     *
     * @param request
     * @param callback
     */
    public void enqueue(Request request, Callback callback) {
        okHttpClient.newCall(request).enqueue(callback);
    }


    /**
     * 获取MIME类型
     *
     * @param fileName 文件名称 如 readme.txt 则返回text/plain
     */
    public MediaType getMediaType(String fileName) {
        return MediaType.parse(typeMap.getContentType(fileName));
    }

    /**
     * 获取MIME类型
     *
     * @param file 文件 如 readme.txt 则返回text/plain
     */
    public MediaType getMediaType(File file) {
        return MediaType.parse(typeMap.getContentType(file));
    }

    /**
     * Map转换FormBody
     *
     * @param params
     * @return
     */
    private RequestBody map2FormBody(Map<String, Object> params) {
        FormBody.Builder builder = new FormBody.Builder();
        params.forEach((key, value) -> {
            builder.add(key, value.toString());
        });
        return builder.build();
    }
}
